﻿/*----------------------------------------------------------------
//  <copyright file="DbContextBase.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-01-30 14:32</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.Entity
{
    #region "数据上下文基类"
    /// <summary>
    /// 数据上下文基类
    /// </summary>
    public abstract class DbContextBase : DbContext, IDbContext
    {
        //字段
        private readonly IEntityManager _entityManager;
        private readonly DbContextOption _dbContextOptions;
        private readonly IServiceProvider _serviceProvider;

        #region "属性"
        #region "获取 日志对象"
        /// <summary>
        /// 获取 日志对象
        /// </summary>
        protected ILogger Logger { get; }
        #endregion
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus { get; }
        #endregion
        #region "获取 数据审计信息提供者"
        /// <summary>
        /// 获取 数据审计信息提供者
        /// </summary>
        protected IAuditEntityProvider AuditEntityProvider { get; }
        #endregion
        #region "获取 实体条目事件信息提供者"
        /// <summary>
        /// 获取 实体条目事件信息提供者
        /// </summary>
        protected IEntityEntryProvider EntityEntryProvider { get; }
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个数据上下文基类的新实例"
        /// <summary>
        /// 初始化一个数据上下文基类 <see cref="DbContextBase"/> 的新实例
        /// </summary>
        /// <param name="options"></param>
        /// <param name="serviceProvider"></param>
        protected DbContextBase(DbContextOptions options, IServiceProvider serviceProvider)
            : base(options)
        {
            _serviceProvider = serviceProvider;
            _entityManager = serviceProvider.GetService<IEntityManager>();
            //_dbContextOptions = serviceProvider?.GetMicroCloudOptions()?.DbContexts?.Values.FirstOrDefault(m => m.DbContextType == GetType());
            _dbContextOptions = serviceProvider?.GetMicroCloudOptions()?.GetDbContextOptions(GetType());
            Logger = serviceProvider.GetLogger(this);
            EventBus = serviceProvider.GetService<IEventBus>();
            AuditEntityProvider = serviceProvider.GetService<IAuditEntityProvider>();
            EntityEntryProvider = serviceProvider.GetService<IEntityEntryProvider>();
        }
        #endregion

        #endregion

        #region "方法"
        #region "将在此上下文中所做的所有更改保存到数据库中，同时自动开启事务或使用现有同连接事务"
        /// <summary>
        ///     将在此上下文中所做的所有更改保存到数据库中，同时自动开启事务或使用现有同连接事务
        /// </summary>
        /// <remarks>
        ///     此方法将自动调用 <see cref="M:Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges" /> 
        ///     若要在保存到基础数据库之前发现对实体实例的任何更改，请执行以下操作。这可以通过以下类型禁用
        ///     <see cref="P:Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.AutoDetectChangesEnabled" />.
        /// </remarks>
        /// <returns>
        ///     写入数据库的状态项的数目。
        /// </returns>
        /// <exception cref="T:Microsoft.EntityFrameworkCore.DbUpdateException">
        ///     保存到数据库时遇到错误。
        /// </exception>
        /// <exception cref="T:Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException">
        ///     保存到数据库时会遇到并发冲突。
        ///     当在保存期间影响到意外数量的行时，就会发生并发冲突。
        ///     这通常是因为数据库中的数据在加载到内存后已经被修改。
        /// </exception>
        public override int SaveChanges()
        {
            List<AuditEntityEntry> auditEntries = [];
            if (_dbContextOptions.EntityAuditEnabled == true)
            {
                auditEntries = AuditEntityProvider?.GetAuditEntries(this);
            }
            List<Events.EntityEntry> operateEntries = [];
            if (_dbContextOptions.EntityEventEnabled == true)
            {
                operateEntries = EntityEntryProvider?.GetEntityEntries(this);
            }

            //开启或使用现有事务
            ScopedDictionary dict = _serviceProvider.GetService<ScopedDictionary>();
            BeginOrUseTransaction(dict?.IsolationLevel);

            int count;
            try
            {
                count = base.SaveChanges();
            }
            catch (System.Exception ex)
            {
                string msg = ex.Message;
                while (ex.InnerException != null)
                {
                    msg += $"---{ex.InnerException.Message}";
                    ex = ex.InnerException;
                }
                Logger.LogError(ex, "{msg}", msg);
                throw;
            }
            if (count > 0)
            {
                if (auditEntries?.Count > 0)
                {
                    //发布数据审计事件
                    EventBus?.Publish(this, new AuditEntityEventData(auditEntries));
                }
                if (operateEntries?.Count > 0)
                {
                    //发布数据操作事件
                    EventBus?.Publish(this, new EntityEntryEventData(operateEntries, this));
                }
            }

            return count;
        }
        #endregion
        #region "异步地将此上下文中的所有更改保存到数据库中，同时自动开启事务或使用现有同连接事务"
        /// <summary>
        ///     异步地将此上下文中的所有更改保存到数据库中，同时自动开启事务或使用现有同连接事务
        /// </summary>
        /// <remarks>
        ///     <para>
        ///         此方法将自动调用 <see cref="M:Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges" /> 
        ///         若要在保存到基础数据库之前发现对实体实例的任何更改，请执行以下操作。这可以通过以下类型禁用
        ///         <see cref="P:Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.AutoDetectChangesEnabled" />.
        ///     </para>
        ///     <para>
        ///         不支持同一上下文实例上的多个活动操作。请使用“等待”确保在此上下文上调用其他方法之前任何异步操作都已完成。
        ///     </para>
        /// </remarks>
        /// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
        /// <returns>
        ///     表示异步保存操作的任务。任务结果包含写入数据库的状态条目数。
        /// </returns>
        /// <exception cref="T:Microsoft.EntityFrameworkCore.DbUpdateException">
        ///     保存到数据库时遇到错误。
        /// </exception>
        /// <exception cref="T:Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException">
        ///     保存到数据库时会遇到并发冲突。
        ///     当在保存期间影响到意外数量的行时，就会发生并发冲突。
        ///     这通常是因为数据库中的数据在加载到内存后已经被修改。
        /// </exception>
        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
        {
            List<AuditEntityEntry> auditEntries = [];
            if (_dbContextOptions.EntityAuditEnabled == true)
            {
                auditEntries = AuditEntityProvider?.GetAuditEntries(this);
            }
            List<Events.EntityEntry> operateEntries = [];
            if (_dbContextOptions.EntityEventEnabled == true)
            {
                operateEntries = EntityEntryProvider?.GetEntityEntries(this);
            }

            //开启或使用现有事务
            ScopedDictionary dict = _serviceProvider.GetService<ScopedDictionary>();
            await BeginOrUseTransactionAsync(dict?.IsolationLevel, cancellationToken);

            int count;
            try
            {
                count = await base.SaveChangesAsync(cancellationToken);
            }
            catch (System.Exception ex)
            {
                string msg = ex.Message;
                while (ex.InnerException != null)
                {
                    msg += $"---{ex.InnerException.Message}";
                    ex = ex.InnerException;
                }
                Logger.LogError(ex, "{msg}", msg);
                throw;
            }
            if (count > 0)
            {
                if (auditEntries?.Count > 0)
                {
                    //发布数据审计事件
                    await EventBus?.PublishAsync(this, new AuditEntityEventData(auditEntries));
                }
                if (operateEntries?.Count > 0)
                {
                    //发布数据操作事件
                    await EventBus?.PublishAsync(this, new EntityEntryEventData(operateEntries, this));
                }
            }

            return count;
        }
        #endregion
        #region "开启或使用现有事务"
        /// <summary>
        /// 开启或使用现有事务
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        public void BeginOrUseTransaction(IsolationLevel? isolationLevel = null)
        {
            IUnitOfWork unitOfWork = _serviceProvider.GetService<IUnitOfWork>();
            unitOfWork?.BeginOrUseTransaction(this, isolationLevel);
        }
        #endregion

        #region "异步开启或使用现有事务"
        /// <summary>
        /// 异步开启或使用现有事务
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <param name="cancellationToken">任务取消标识</param>
        /// <returns></returns>
        public async Task BeginOrUseTransactionAsync(IsolationLevel? isolationLevel = null, CancellationToken cancellationToken = default)
        {
            IUnitOfWork unitOfWork = _serviceProvider.GetService<IUnitOfWork>();
            if (unitOfWork != null)
            {
                await unitOfWork.BeginOrUseTransactionAsync(this, isolationLevel, cancellationToken);
            }
        }
        #endregion

        #region "是否已启用事务"
        /// <summary>
        /// 是否已启用事务
        /// </summary>
        /// <returns></returns>
        public bool IsEnableTransaction()
        {
            var dbContext = this as DbContext;
            return dbContext.Database.CurrentTransaction != null;
        }
        #endregion

        #region "获取实体数据表默认架构"
        /// <summary>
        /// 获取实体数据表默认架构
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据表架构</returns>
        public string GetTableDefaultSchema(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetDefaultSchema();
        }
        #endregion
        #region "获取实体数据表架构"
        /// <summary>
        /// 获取实体数据表架构
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据表架构</returns>
        public string GetTableSchema(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetSchema();
        }
        #endregion
        #region "获取实体数据表名称"
        /// <summary>
        /// 获取实体数据表名称
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据表名称</returns>
        public string GetTableName(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetTableName();
        }
        #endregion
        #region "获取实体数据列数组"
        /// <summary>
        /// 获取实体数据列数组
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns></returns>
        public IDictionary<string, string> GetTableColumns(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            var dict = new Dictionary<string, string>();
            var properties = Model.FindEntityType(entityType).GetProperties();
            foreach (var p in properties)
            {
                //dict.Add(p.Name, p.GetColumnBaseName());
                dict.Add(p.Name, p.GetColumnName());
            }
            return dict;
        }
        #endregion
        #region "获取实体主键列数组"
        /// <summary>
        /// 获取实体主键列数组
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns></returns>
        public IDictionary<string, string> GetTablePrimaryKeyColumns(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            var dict = new Dictionary<string, string>();
            var primaryKey = Model.FindEntityType(entityType).FindPrimaryKey();
            var properties = primaryKey.Properties;
            foreach (var p in properties)
            {
                //dict.Add(p.Name, p.GetColumnBaseName());
                dict.Add(p.Name, p.GetColumnName());
            }
            return dict;
        }
        #endregion

        #region "获取实体数据视图默认架构"
        /// <summary>
        /// 获取实体数据视图默认架构
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据视图架构</returns>
        public string GetDefaultViewSchema(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetDefaultViewSchema();
        }
        #endregion
        #region "获取实体数据视图架构"
        /// <summary>
        /// 获取实体数据视图架构
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据视图架构</returns>
        public string GetViewSchema(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetViewSchema();
        }
        #endregion
        #region "获取实体数据视图名称"
        /// <summary>
        /// 获取实体数据视图名称
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>映射的数据视图名称</returns>
        public string GetViewName(Type entityType)
        {
            Check.NotNull(entityType, nameof(entityType));

            return Model.FindEntityType(entityType).GetViewName();
        }
        #endregion

        #region "是否是关系型数据库"
        /// <summary>
        /// 是否是关系型数据库
        /// </summary>
        /// <returns></returns>
        public bool IsRelationalTransaction()
        {
            var dbContext = this as DbContext;
            return dbContext.IsRelationalTransaction();
        }
        #endregion
        #region "关系型数据库是否存在"
        /// <summary>
        /// 关系型数据库是否存在
        /// </summary>
        /// <returns></returns>
        public bool ExistsRelationalDatabase()
        {
            var dbContext = this as DbContext;
            return dbContext.ExistsRelationalDatabase();
        }
        #endregion

        #region "获取数据上下文配置选项"
        /// <summary>
        /// 获取数据上下文配置选项
        /// </summary>
        /// <returns>数据上下文配置选项</returns>
        public DbContextOption GetOptions()
        {
            var context = this as DbContext;
            MicroCloudOptions options = context.GetService<IConfiguration>()?.GetMicroCloudOptions();
            if (options != null)
            {
                return options.DbContexts.First(m => m.Value.DbContextType == context.GetType()).Value;
            }

            return null;
        }
        #endregion
        #region "获取数据库类型"
        /// <summary>
        /// 获取数据库类型
        /// </summary>
        /// <returns>数据库类型枚举</returns>
        public DatabaseType GetDatabaseType()
        {
            var options = GetOptions();
            if (options != null)
            {
                return options.DatabaseType;
            }
            return DatabaseType.SqlServer;
        }
        #endregion
        #region "获取数据库连接字符串"
        /// <summary>
        /// 获取数据库连接字符串
        /// </summary>
        /// <returns>数据库连接字符串</returns>
        public string GetConnectionString()
        {
            var options = GetOptions();
            if (options != null)
            {
                return options.ConnectionString;
            }
            return GetDbConnection().ConnectionString;
        }
        #endregion

        #region "基于原始SQL查询创建LINQ查询，该查询返回数据库提供程序本机支持的标量类型的结果集。"
        /// <summary>
        /// 基于原始SQL查询创建LINQ查询，该查询返回数据库提供程序本机支持的标量类型的结果集。
        /// </summary>
        /// <param name="sql">带参数的SQL查询的插值字符串</param>
        /// <returns>受影响的行数</returns>
        public IQueryable<TResult> SqlQuery<TResult>(FormattableString sql)
        {
            return Database.SqlQuery<TResult>(sql);
        }
        #endregion
        #region "基于原始SQL查询创建LINQ查询，该查询返回数据库提供程序本机支持的标量类型的结果集。"
        /// <summary>
        /// 基于原始SQL查询创建LINQ查询，该查询返回数据库提供程序本机支持的标量类型的结果集。
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>受影响的行数</returns>
        public IQueryable<TResult> SqlQueryRaw<TResult>(string sql, params object[] parameters)
        {
            return Database.SqlQueryRaw<TResult>(sql, parameters);
        }
        #endregion
        #region "执行Sql"
        /// <summary>
        /// 执行Sql
        /// </summary>
        /// <param name="sql">带参数的SQL查询的插值字符串</param>
        /// <returns>受影响的行数</returns>
        public int ExecuteSql(FormattableString sql)
        {
            return Database.ExecuteSql(sql);
        }
        #endregion
        #region "异步执行Sql"
        /// <summary>
        /// 异步执行Sql
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <returns>受影响的行数</returns>
        public async Task<int> ExecuteSqlAsync(FormattableString sql)
        {
            return await Database.ExecuteSqlAsync(sql);
        }
        #endregion
        #region "执行指定的Sql语句"
        /// <summary>
        /// 执行指定的Sql语句
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>受影响的行数</returns>
        public int ExecuteSqlRaw(string sql, params object[] parameters)
        {
            return Database.ExecuteSqlRaw(sql, parameters);
        }
        #endregion
        #region "异步执行指定的Sql语句"
        /// <summary>
        /// 异步执行指定的Sql语句
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>受影响的行数</returns>
        public async Task<int> ExecuteSqlRawAsync(string sql, params object[] parameters)
        {
            return await Database.ExecuteSqlRawAsync(sql, parameters);
        }
        #endregion
        #region "执行指定的格式化Sql语句"
        /// <summary>
        /// 执行指定的格式化Sql语句
        /// </summary>
        /// <param name="sql">带参数的SQL查询的插值字符串</param>
        /// <returns>受影响的行数</returns>
        public int ExecuteSqlInterpolated(FormattableString sql)
        {
            return Database.ExecuteSqlInterpolated(sql);
        }
        #endregion
        #region "异步执行指定的格式化Sql语句"
        /// <summary>
        /// 异步执行指定的格式化Sql语句
        /// </summary>
        /// <param name="sql">带参数的SQL查询的插值字符串</param>
        /// <returns>受影响的行数</returns>
        public async Task<int> ExecuteSqlInterpolatedAsync(FormattableString sql)
        {
            return await Database.ExecuteSqlInterpolatedAsync(sql);
        }
        #endregion

        #region "执行指定的Sql语句并返回DataSet数据"
        /// <summary>
        /// 执行指定的Sql语句并返回DataSet数据
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>DataSet数据</returns>
        public DataSet SqlQueryToDataSet(string sql, params object[] parameters)
        {
            DbCommand cmd = CreateDbCommand(out _);
            cmd.CommandText = sql;
            CombineParams(ref cmd, parameters);

            using DbDataReader reader = cmd.ExecuteReader();
            var ds = ToDataSet(reader);
            reader.Close();
            //设置名称
            ds.DataSetName = "DS"; // "Connection";
            for (int i = 0; i < ds.Tables.Count; i++)
            {
                var table = ds.Tables[i];
                table.TableName = $"TB_{i}";
            }
            //conn.Close();
            return ds;
        }
        #endregion
        #region "异步执行指定的Sql语句并返回DataSet数据"
        /// <summary>
        /// 异步执行指定的Sql语句并返回DataSet数据
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>DataSet数据</returns>
        public async Task<DataSet> SqlQueryToDataSetAsync(string sql, params object[] parameters)
        {
            DbCommand cmd = CreateDbCommand(out _);
            cmd.CommandText = sql;
            CombineParams(ref cmd, parameters);

            using DbDataReader reader = await cmd.ExecuteReaderAsync();
            var ds = ToDataSet(reader);
            reader.Close();
            //设置名称
            ds.DataSetName = "DS"; // "Connection";
            for (int i = 0; i < ds.Tables.Count; i++)
            {
                var table = ds.Tables[i];
                table.TableName = $"TB_{i}";
            }
            //conn.Close();
            return ds;
        }
        #endregion

        #region "执行指定的Sql语句并返回DataTable数据"
        /// <summary>
        /// 执行指定的Sql语句并返回DataTable数据
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>DataTable数据</returns>
        public DataTable SqlQueryToDataTable(string sql, params object[] parameters)
        {
            DbCommand cmd = CreateDbCommand(out _);
            cmd.CommandText = sql;
            CombineParams(ref cmd, parameters);

            using DbDataReader reader = cmd.ExecuteReader();
            using DataTable dt = new();
            dt.Load(reader);
            reader.Close();
            //conn.Close();
            return dt;
        }
        #endregion
        #region "异步执行指定的Sql语句并返回DataTable数据"
        /// <summary>
        /// 异步执行指定的Sql语句并返回DataTable数据
        /// </summary>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>DataTable数据</returns>
        public async Task<DataTable> SqlQueryToDataTableAsync(string sql, params object[] parameters)
        {
            DbCommand cmd = CreateDbCommand(out _);
            cmd.CommandText = sql;
            CombineParams(ref cmd, parameters);

            using DbDataReader reader = await cmd.ExecuteReaderAsync();
            using DataTable dt = new();
            dt.Load(reader);
            await reader.CloseAsync();
            //await conn.CloseAsync();
            return dt;
        }
        #endregion

        #region "执行指定的Sql语句并返回指定类型数据"
        /// <summary>
        /// 执行指定的Sql语句并返回指定类型数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>指定类型数据集合</returns>
        public List<T> SqlQueryToModel<T>(string sql, params object[] parameters) where T : class, new()
        {
            DataTable dt = SqlQueryToDataTable(sql, parameters);
            return dt.ToModel<T>();
        }
        #endregion
        #region "异步执行指定的Sql语句并返回指定类型数据"
        /// <summary>
        /// 异步执行指定的Sql语句并返回指定类型数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="sql">要执行的SQL</param>
        /// <param name="parameters">要与SQL一起使用的参数</param>
        /// <returns>指定类型数据集合</returns>
        public async Task<List<T>> SqlQueryToModelAsync<T>(string sql, params object[] parameters) where T : class, new()
        {
            DataTable dt = await SqlQueryToDataTableAsync(sql, parameters);
            return dt.ToModel<T>();
        }
        #endregion

        #region "获取数据库连接"
        /// <summary>
        /// 获取数据库连接
        /// </summary>
        /// <returns>数据库连接对象</returns>
        public DbConnection GetDbConnection()
        {
            var dbConnection = Database.GetDbConnection();
            return dbConnection;
        }
        #endregion
        #region "创建数据库命令"
        /// <summary>
        /// 创建数据库命令
        /// </summary>
        /// <param name="dbConnection">数据库连接对象</param>
        /// <returns>数据库命令对象</returns>
        public DbCommand CreateDbCommand(out DbConnection dbConnection)
        {
            dbConnection = GetDbConnection();
            switch (dbConnection.State)
            {
                case ConnectionState.Closed:    //连接已关闭。
                    dbConnection.Open();
                    break;
                case ConnectionState.Open:  //连接已打开。
                case ConnectionState.Connecting:    //连接对象正在连接到数据源。
                case ConnectionState.Executing: //连接对象正在执行命令。（此值为产品的未来版本保留。）
                case ConnectionState.Fetching:  //连接对象正在检索数据。（此值为产品的未来版本保留。）
                    break;
                case ConnectionState.Broken:    //与数据源的连接已断开。这只能在连接打开后发生。此状态下的连接可以关闭，然后重新打开。（此值为产品的未来版本保留。）
                    dbConnection.Close();
                    dbConnection.Open();
                    break;
            }
            DbCommand dbCommand = dbConnection.CreateCommand();
            var dbTransaction = Database.CurrentTransaction?.GetDbTransaction();
            if (dbTransaction != null)
            {
                dbCommand.Transaction = dbTransaction;
            }
            return dbCommand;
        }
        #endregion

        #endregion

        #region "受保护的方法"
        #region "重写以配置要用于此上下文的数据库和其他选项"
        /// <summary>
        /// 重写以配置要用于此上下文的数据库和其他选项
        /// </summary>
        /// <param name="optionsBuilder">上下文数据选项构建器</param>
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //注入DbContextOptionsBuilder
            base.OnConfiguring(optionsBuilder);
        }
        #endregion
        #region "创建上下文数据模型时对各个实体类的数据库映射细节进行配置"
        /// <summary>
        /// 创建上下文数据模型时对各个实体类的数据库映射细节进行配置
        /// </summary>
        /// <param name="modelBuilder">上下文数据模型构建器</param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {          
            //注入ModelBuilder
            base.OnModelCreating(modelBuilder);

            //通过实体配置信息将实体注册到当前上下文
            Type contextType = GetType();
            IEntityRegister[] registers = _entityManager.GetEntityRegisters(contextType);
            foreach (IEntityRegister register in registers)
            {
                register.RegisterTo(modelBuilder);
                Logger.LogDebug("将实体 {entityType} 注册到上下文 {contextType} 中", register.EntityType, contextType);
            }
            Logger.LogInformation("上下文 {contextType} 注册了 {length} 个实体类", contextType, registers.Length);

            //应用批量实体配置
            List<IMutableEntityType> mutableEntityTypes = modelBuilder.Model.GetEntityTypes().ToList();
            IEntityBatchConfiguration[] entityBatchConfigurations = _serviceProvider.GetServices<IEntityBatchConfiguration>().ToArray();
            if (entityBatchConfigurations?.Length > 0)
            {
                foreach (IMutableEntityType mutableEntityType in mutableEntityTypes)
                {
                    foreach (IEntityBatchConfiguration entityBatchConfiguration in entityBatchConfigurations)
                    {
                        entityBatchConfiguration.Configure(modelBuilder, mutableEntityType, Database, _dbContextOptions, GetType());
                    }
                }
            }
        }
        #endregion

        #region "组合参数"
        /// <summary>
        /// 组合参数
        /// </summary>
        /// <param name="command">数据命令</param>
        /// <param name="parameters">参数</param>
        protected virtual void CombineParams(ref DbCommand command, params object[] parameters)
        {
            if (parameters != null)
            {
                var databaseType = GetDatabaseType();
                foreach (DbParameter parameter in parameters.Cast<DbParameter>())
                {
                    switch (databaseType)
                    {
                        case DatabaseType.Sqlite:
                            break;
                        case DatabaseType.MySql:
                            //if (!parameter.ParameterName.Contains('?'))
                            //{
                            //    parameter.ParameterName = $"?{parameter.ParameterName}";
                            //}
                            break;
                        case DatabaseType.SqlServer:
                            if (!parameter.ParameterName.Contains('@'))
                            {
                                parameter.ParameterName = $"@{parameter.ParameterName}";
                            }
                            break;
                        case DatabaseType.PostgreSql:
                        case DatabaseType.Oracle:
                            break;
                    }
                    command.Parameters.Add(parameter);
                }
            }
        }
        #endregion

        #region "将DbDataReader转换为DataSet"
        /// <summary>
        /// 将DbDataReader转换为DataSet
        /// </summary>
        /// <param name="dataReader"></param>
        /// <returns></returns>
        protected virtual DataSet ToDataSet(DbDataReader dataReader)
        {
            if (dataReader == null)
            {
                return null;
            }
            DataSet dataSet = new();
            if (!dataReader.HasRows)
            {
                dataSet.Tables.Add(new DataTable());
                return dataSet;
            }
            for (; ; )
            {
                DataTable dataTable = new();
                try
                {
                    int fieldCount = dataReader.VisibleFieldCount;
                    for (int i = 0; i < fieldCount; i++)
                    {
                        string fieldName = dataReader.GetName(i);
                        Type fieldType = dataReader.GetFieldType(i);
                        dataTable.Columns.Add(new DataColumn(fieldName, fieldType));
                    }
                    while (dataReader.Read())
                    {
                        object[] rowValues = new object[fieldCount];
                        dataReader.GetValues(rowValues);
                        dataTable.Rows.Add(rowValues);
                    }
                    dataSet.Tables.Add(dataTable);
                    if (!dataReader.NextResult())
                    {
                        return dataSet;
                    }
                }
                catch (System.Exception)
                {
                    foreach (DataTable p in dataSet.Tables)
                    {
                        try
                        {
                            p?.Dispose();
                        }
                        catch (System.Exception) { }
                    }
                    try
                    {
                        dataTable.Dispose();
                    }
                    catch (System.Exception) { }
                    try
                    {
                        dataSet.Dispose();
                    }
                    catch (System.Exception) { }
                    return null;
                }
            }
        }
        #endregion

        #endregion

    }
    #endregion

}
